作天已將「寶寶列表 (BabyListActivity)」所有實作細節都說明完畢了,今天我們回到「新增/編輯寶寶」尚未介紹的部分,今天先介紹「寶寶大頭照」的處理,程式讓使用者從兩種管道選取照片:(1) 從內建的相片集程式 (或其它相片管理軟體) 中選取照片;(2) 透過相機拍攝來獲得照片。關於透過相機拍攝來獲得照片的方法可參考筆者的書籍 [1],這篇文章只專注介紹從內建的相片集程式中選取照片。相關的程式碼片段如下所示:
private void showPhotoSourceDialog() {
LayoutInflater inflater = LayoutInflater.from(this);
View view = inflater.inflate(R.layout.dialog_headshotsource, null);
ImageView iv_photo = (ImageView)view.findViewById(R.id.iv_photo);
iv_photo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ad.dismiss();
Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
photoPickerIntent.setType("image/*");
startActivityForResult(photoPickerIntent, PHOTO_PICKER);
}
});
ImageView iv_camera = (ImageView)view.findViewById(R.id.iv_camera);
AlertDialog.Builder adb = new AlertDialog.Builder(this);
ad = adb.create();
ad.setView(view);
ad.show();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == PHOTO_PICKER) {
if (resultCode == RESULT_OK) {
Uri uri = data.getData();
String picturepath = getPathFromUri(uri);
Log.d("LINCYU", "Picture Path: " + picturepath);
baby.headshot = picturepath;
Bitmap bitmap = Util.decodeFile(picturepath, 256);
iv_headshot.setImageBitmap(bitmap);
}
}
}
private String getPathFromUri(Uri uri) {
String[] filePathColumn = { MediaStore.Images.Media.DATA };
Cursor cursor = getContentResolver().query(uri, filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
cursor.close();
return picturePath;
}
昨天已經介紹過 AlertDialog.Builder 的範例,然而今天有點不太一樣,我們不是直接呼叫 AlertDialog.Builder 物件的方法來設定對話框,而是呼叫 AlertDialog.Builder 物件的 create 方法來產生一個 AlertDialog 物件,再呼叫 AlertDialog 物件的方法來設定對話框,為什麼要這樣做呢?這是因為昨天的對話框有兩個按鈕(「取消」和「刪除資料」),這兩個按鈕按下後,對話框就會消失,今天的對話框沒有這樣的按鈕,我們必須呼叫 AlertDialog 物件的 dismiss 讓對話框消失 (AlertDialog.Builder 物件沒有 dismiss 方法可呼叫)。
這個對話框的主體有兩個 ImageView,按下 iv_photo 後可讓使用者從內建的相片集程式中選取照片,做法是使用先前介紹過的 Implicit Intent,現在來討論 onClick 裡面的內容,首先呼叫 AlertDialog 物件的 dismiss 將對話框關掉,接著設定 Implicit Intent,ACTION 設為 ACTION_PICK,接著利用 setType 設定想選取的是「圖 (Image)」,setType 的參數為 MIME Type [2],接著呼叫 startActivityForResult 來啟動內建相片集程式。
先前我們已經學過利用 startActivity 啟動一個新的 Activity,並且透過 Intent 攜帶資料給新的 Activity,那麼新的Activity若想將資料回傳該怎麼達成?我們要使用 startActivityForResult 取代startActivity,當您希望被呼叫的Activity能在結束時回傳資料的話,就應該使用startActivityForResult,這個Method需要兩個參數,第一個參數是Intent,已經不需再多說,第二個參數是「請求碼」,這個請求碼是用來分辨是哪個 Activity 回傳的 (詳細說明可參考筆者書籍 [1])。
我們還必須覆寫 onActivityResult 處理新的 Activity 所回傳的資料 (在我們的例子中,這個新的 Activity 為內建相片集程式),onActivityResult會傳入三個參數,第一個參數是請求碼,我們可藉著請求碼來判斷資料是哪一個被呼叫的 Activity 所回傳的 (也就是 startActivityForResult 的第二個參數),第二個參數是結果碼,通常若執行正常會回傳 RESULT_OK,第三個參數是Intent,回傳的資料可從Intent中取得。在我們的範例中,我們先取出圖檔的 URI,並把這個 URI 轉換成 SD 卡上的路徑 (記得必須於 AndroidManifest.xml 宣告相關的 Permissions),最後讀取此圖黨並轉換成 Bitmap 物件後顯示於 ImageView 上,把檔案轉成 Bitmap 物件的方法可參考 [3] 和 [4]。
最後要提醒的是,viewInitialization 中關於 iv_headshot 的程式碼也必須跟著改寫:
iv_headshot = (ImageView)findViewById(R.id.iv_headshot);
Bitmap bitmap = Util.decodeFile(baby.headshot, 256);
if (bitmap != null) {
iv_headshot.setImageBitmap(bitmap);
}
iv_headshot.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
showPhotoSourceDialog();
}
});
今天的文章主要介紹從內建的相片集程式中選取照片。由於我們自己的程式會從 SD 卡上讀取照片,Permission 的宣告會於明天做說明,而更多 startActivityForResult 的範例以及如何透過相機拍攝來獲得照片,請讀者自行參考筆者的書籍 [1]。
最後附上程式的執行結果畫面:
參考資料
[1] 林致宇, Android程式設計入門與應用(附範例光碟), 全華出版社, ISBN: 9789572194126, http://www.opentech.com.tw/search/bookinfo.asp?isbn=9789572194126&companyID=04383129
[2] Internet media type - Wikipedia, the free encyclopedia, http://en.wikipedia.org/wiki/Internet_media_type
[3] android - Resizing bitmap from InputStream - Stack Overflow, http://stackoverflow.com/questions/12841482/resizing-bitmap-from-inputstream
[4] Android: How to load image into Bitmap - Stack Overflow, http://stackoverflow.com/questions/4887297/android-how-to-load-image-into-bitmap